#include "array.h"

Array* ArrayCreate(int capacity) {
  Array* array = (Array *)malloc(sizeof(Array));
  array->length = 0;
  array->capacity = capacity;
  array->data = (void **)malloc(sizeof(void*) * capacity);
  return array;
}

void ArrayDestroy(void* data) {
  if (data) {
    Array* array = (Array *)data;
    if (array->data) {
      free(array->data);
    }
    free(array);
  }
}

static Array* ArrayResize(Array* array, int size) {
  if (size < array->capacity) return array;
  array->capacity = size;
  array->data = (void **)realloc(array->data, sizeof(void*) * size);
  return array;
}

int ArrayInsert(Array* array, int index, void* item) {
  if (array->length == array->capacity) {
    ArrayResize(array, array->capacity * 2);
  }
  if (index < 0) index = 0;
  
  if (index >= array->length) {
    array->data[array->length++] = item;
  } else {
    memmove(array->data + index + 1, array->data + index, (array->length - index) * sizeof(void *));
    array->data[index] = item;
    array->length++;
  }
  return 1;
}

void* ArrayRemoveByIndex(Array* array, int index) {
  if (index < 0 || index >= array->length || array->length == 0) return NULL;
  void* t = array->data[index];
  if (index != array->length - 1) {
    memmove(array->data + index, array->data + index + 1, (array->length - index - 1) * sizeof(void *));
  }
  array->length--;
  return t;
}

void* ArrayRemove(Array* array, void* item) {
  for (int i = 0; i < array->length; i++) {
    if (item == array->data[i]) {
      return ArrayRemoveByIndex(array, i);
    }
  }
  return NULL;
}

int ArrayPushBack(Array* array, void* item) {
  return ArrayInsert(array, array->length, item);
}

void* ArrayPopBack(Array* array) {
  return ArrayRemoveByIndex(array, array->length - 1);
}

static void** ArrayNext(ArrayIterator* itr) {
  if (itr->array == NULL || itr->index >= itr->array->length) {
    return NULL;
  }
  void** t = itr->array->data + itr->index;
  itr->index++;
  return t;
}

static void ArrayIteratorReset(ArrayIterator* itr) {
  itr->index = 0;
}

ArrayIterator ArrayGetIterator(Array* array) {
  ArrayIterator itr;
  itr.array = array;
  itr.index = 0;
  itr.next = ArrayNext;
  itr.reset = ArrayIteratorReset;
  return itr;
}
